/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit.features.test_instantiator;

import picounit.Lifecycle;
import picounit.features.class_finder.ClassFinder;
import picounit.features.signature_factory.SignatureFactory;

import java.lang.reflect.InvocationTargetException;

public class DefaultTestInstantiator implements TestInstantiator {
	private final Instantiator instantiator;
	private final Invoker invoker;
	private final LifecycleInstantiator lifecycleInstantiator;

	public static TestInstantiator create(SignatureFactory signatureFactory, ClassLoader classLoader,
		ClassFinder classFinder) {

		Instantiator instantiator = new OrdinaryInstantiator(signatureFactory);

		return new DefaultTestInstantiator(instantiator, new Invoker(signatureFactory),
			new LifecycleInstantiatorImpl(classLoader, instantiator, classFinder));
	}

	public DefaultTestInstantiator(Instantiator instantiator, Invoker invoker,
		LifecycleInstantiator lifecycleInstantiator) {

		this.instantiator = instantiator;
		this.invoker = invoker;
		this.lifecycleInstantiator = lifecycleInstantiator;
	}

	public <T> T instantiate(Class<T> testClass) {
		try {
			setUp(getLifecycles(testClass));
			
			return instantiator.instantiate(testClass);
		}
		catch (IllegalArgumentException illegalArgumentException) {
			throw new TestInstantiationException(illegalArgumentException);
		}
		catch (IllegalAccessException illegalAccessException) {
			throw new TestInstantiationException(illegalAccessException);
		}
		catch (InvocationTargetException invocationTargetException) {
			throw new TestInstantiationException(invocationTargetException);
		}
		catch (InstantiationException instantiationException) {
			throw new TestInstantiationException(instantiationException);
		}
		catch (ClassNotFoundException classNotFoundException) {
			throw new TestInstantiationException(classNotFoundException);
		}
	}

	private Lifecycle[] getLifecycles(Class testClass) throws IllegalArgumentException,
		InstantiationException, IllegalAccessException, ClassNotFoundException, InvocationTargetException {

		return lifecycleInstantiator.instantiateLifecyclesFor(testClass);
	}

	private void setUp(Lifecycle[] lifecycles) throws IllegalAccessException, InvocationTargetException {
		for (Lifecycle lifecycle : lifecycles) {
			setUp(lifecycle);
		}
	}

	private void setUp(Object target) throws IllegalAccessException, InvocationTargetException {
		invoker.invoke("setUp", target);
	}
}
